package utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

import models.User;

import play.libs.WS;
import play.libs.WS.HttpResponse;
import play.libs.WS.WSRequest;
import play.mvc.Http;

public class C2DM {

	/**
	 * constants
	 */
	private final static String C2DM_URL = "http://android.apis.google.com/c2dm/send";
	private final static String AUTHTOKEN_URL = "https://www.google.com/accounts/ClientLogin";
	private final static String APP_MAIL = "wassaltapp@gmail.com";
	private final static String APP_PWD = "wassalt-lesa";
	private static final String APP_NAME = "wassalt-1.0";
	private final static String ACCOUNT_TYPE_VALUE = "GOOGLE";
	private static final String SERVICE_VALUE = "ac2dm";
	private static String authToken = null;

	/**
	 * gets the user from the DB if it's there and has a C2DM key it sends msg
	 * to c2dm server
	 * 
	 * @param phone
	 *            phone number of user to send msg to
	 * @param collabKey
	 *            label key used by C2DM server to collapse similar messages and
	 *            send the latest
	 * @param msg
	 *            the message to be send to the client
	 * @return true in case of success and false in case of failure
	 * 
	 */
	public static boolean push(String phone, String collabKey, String msg) {
		// get the user to send C2DM to
		User s = User.findByPhone(phone);
		// check if it's registered user
		if (s == null)
			return false;
		// get the device to send to
		String deviceRegKey = s.getDeviceRegKey();
		try {
			// send the message to C2DM server
			send(deviceRegKey, collabKey, msg);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

	}
	

	/**
	 * @param phones
	  label key used by C2DM server to collapse similar messages and
	 *            send the latest
	 * @param msg
	 *            the message to be send to the client
	 * @return list of true or false representing success and failure of sending.
	 * @author Gad
	 */
	public static List<Boolean> pushForgroup(List<String> phones,String collapseKey, String msg){
		List<Boolean> success= new LinkedList<Boolean>();
		for(String phone: phones){
			success.add(push(phone,collapseKey,msg));
		}
		return success;
		
	}


	/**
	 * initialize ssl connection to c2dm server and send the message to be sent
	 * to client
	 * 
	 * @param deviceRegKey
	 *            C2DM registration key
	 * @param collapseKey
	 *            label key used by C2DM server to collapse similar messages and
	 *            send the latest
	 * @param msg
	 *            the message to be send to the client
	 * @return true in case of success and false in case of failure
	 * @author Gad
	 */
	private static boolean send(String deviceRegKey, String collapseKey,
			String msg) {

		if (authToken == null) {
			getAuthToken();
		}
		try {
			System.out.println("\n\ndeviceInfo\n" + deviceRegKey);

			StringBuilder postDataBuilder = new StringBuilder();
			postDataBuilder.append(REG_ID).append(EQ).append(deviceRegKey);
			postDataBuilder.append(AND).append(COLLAPSE_KEY).append(EQ)
					.append(collapseKey);
			postDataBuilder.append(AND).append(PAYLOAD).append(EQ).append(msg);
			byte[] postData = postDataBuilder.toString().getBytes(UTF8);

			URL url = new URL(C2DM_URL);

//			HostnameVerifier hVerifier = new HostnameVerifier() {
//				public boolean verify(String hostname, SSLSession session) {
//					return true;
//				}
//			};

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			//conn.setHostnameVerifier(hVerifier);
			conn.setDoOutput(true);
			conn.setUseCaches(false);
			conn.setRequestMethod(POST);
			conn.setRequestProperty(CONTENT_TYPE, CONTENT_TYPE_VALUE);
			conn.setRequestProperty(CONTENT_LENGTH,
					Integer.toString(postData.length));
			conn.setRequestProperty(AUTHRIZ, GOOGLE_AUTH + authToken);

			// ------------------
			OutputStream out = conn.getOutputStream();
			// --------------------------
			out.write(postData);
			out.close();
			System.out.println("intializing connection to c2dm server");
			int sw = conn.getResponseCode();
			System.out.println("connection initialized");
			// debug
			System.out.println("" + sw);
			switch (sw) {
			case 200: {
				System.out.println("Success, but check for errors in the body");
				BufferedReader br = new BufferedReader(new InputStreamReader(
						(InputStream) conn.getContent()));
				// debug
				String h;
				while ((h = br.readLine()) != null)
					//if (h.equals("InvalidRegistration")||h.equals("NotRegistered"))
					System.out.println(h);
				return true;
			}
			case 401: {
				System.out.println(" Invalid authentication token");
				getAuthToken();
				return send(deviceRegKey, collapseKey, msg);
			}
			default:
				return false;

			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

	}

	/**
	 * To update Google authentication code.
	 */
	private static void getAuthToken() {
		
		
		StringBuffer urlBf=new StringBuffer(AUTHTOKEN_URL);
		urlBf.append("?").append(MAIL).append(EQ).append(APP_MAIL);
		urlBf.append(AND).append(PASSWD).append(EQ).append(APP_PWD);
		urlBf.append(AND).append(SERVICE).append(EQ).append(SERVICE_VALUE);
		urlBf.append(AND).append(SOURCE).append(EQ). append(APP_NAME);
		urlBf.append(AND).append(ACCOUNTTYPE).append(EQ). append(ACCOUNT_TYPE_VALUE);
		System.out.println(urlBf.toString());
		// add headers and parameters
		
		WSRequest request = WS.url(urlBf.toString());
		request.headers.put(CONTENT_TYPE, CONTENT_TYPE_VALUE);

		System.err.println(request.parameters.size());

		// apply request
		HttpResponse response = request.get();

		// get auth value if http success
		if (response.getStatus() == Http.StatusCode.OK) {
			String body = response.getString();
			String[] g = body.split("\n");
			authToken = g[2].substring(5);
			// for debug
			System.err.println(authToken);
		} else
			System.err.println("Cannot get response");
	}
	
	
	

	private final static String EQ = "=";
	private final static String REG_ID = "registration_id";
	private final static String AND = "&";
	private final static String UTF8 = "UTF8";
	private final static String COLLAPSE_KEY = "collapse_key";
	private final static String PAYLOAD = "data.message";
	private final static String POST = "POST";
	private final static String CONTENT_TYPE = "Content-Type";
	private final static String CONTENT_TYPE_VALUE = "application/x-www-form-urlencoded";
	private final static String CONTENT_LENGTH = "Content-Length";
	private final static String AUTHRIZ = "Authorization";
	private final static String GOOGLE_AUTH = "GoogleLogin auth=";
	private final static String ACCOUNTTYPE = "accountType";
	private final static String MAIL = "Email";
	private final static String PASSWD = "Passwd";
	private static final String SERVICE = "service";
	private static final String SOURCE = "scource";

}
